﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Rhino.Mocks;
using Rhino.Mocks.Interfaces;

using SharedGenomics.Workbench.Views;
using SharedGenomics.Workbench.Presenters;

namespace SharedGenomics.Workbench.Tests.Presenters
{
    [TestClass]
    public class FileBrowserPresenterTests
    {
        #region Private Members

        private MockRepository mocks;
        private IOpenFileDialogView openDialog;
        private IFileBrowserView view;

        #endregion

        #region Setup

        [TestInitialize]
        public void Setup()
        {
            this.mocks = new MockRepository();
            this.openDialog = this.mocks.StrictMock<IOpenFileDialogView>();
            this.view = this.mocks.DynamicMock<IFileBrowserView>();
        }

        #endregion

        [TestMethod]
        public void ConstructorTest()
        {
            IOpenFileDialogView openDialog = this.mocks.StrictMock<IOpenFileDialogView>();
            IFileBrowserView view = this.mocks.StrictMock<IFileBrowserView>();

            using (this.mocks.Record())
            {
                //presenter should register for view events
                view.BrowseClicked += null;
                LastCall.IgnoreArguments();

                view.FilePathTextChanged += null;
                LastCall.IgnoreArguments();

                view.OpenClicked += null;
                LastCall.IgnoreArguments();

                //open button should be disabled initially
                view.IsOpenEnabled = false;
            }

            using (this.mocks.Playback())
            {
                var presenter = new FileBrowserPresenter(view, openDialog);
            }
        }

        [TestMethod]
        public void SetFiltersTestValid()
        {
            //presenter should pass on the call to the open file dialog
            this.openDialog.SetFilters("All files | *.*", "Text files | *.txt");
            this.mocks.ReplayAll();

            var presenter = this.CreatePresenter();
            presenter.SetFilters("All files | *.*", "Text files | *.txt");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SetFiltersTestInvalid()
        {
            //presenter should pass on call and propagate exception
            this.openDialog.SetFilters("Invalid filter");
            LastCall.Throw(new ArgumentException("Invalid filter"));

            this.mocks.ReplayAll();

            var presenter = this.CreatePresenter();
            presenter.SetFilters("Invalid filter");
        }

        [TestMethod]
        public void BrowseClickedTestFileSelected()
        {
            IEventRaiser browseEvent;

            using (this.mocks.Record())
            {
                this.view.BrowseClicked += null;
                LastCall.IgnoreArguments();
                browseEvent = LastCall.GetEventRaiser();

                //presenter should show the open file dialog - if a file is selected the file path text on the view should be updated to show the selected file
                this.openDialog.Open();
                LastCall.Return(@"C:\somedirectory\somefile.txt");

                this.view.FilePathText = @"C:\somedirectory\somefile.txt";
            }

            using (this.mocks.Playback())
            {
                var presenter = this.CreatePresenter();

                browseEvent.Raise(null, null);
            }
        }

        [TestMethod]
        public void BrowseClickedTestCancelled()
        {
            IEventRaiser browseEvent;

            using (this.mocks.Record())
            {
                this.view.BrowseClicked += null;
                LastCall.IgnoreArguments();
                browseEvent = LastCall.GetEventRaiser();

                //presenter should show the open file dialog - if a file is selected the file path text on the view should be updated to show the selected file
                this.openDialog.Open();
                LastCall.Return(null);
            }

            using (this.mocks.Playback())
            {
                var presenter = this.CreatePresenter();

                browseEvent.Raise(null, null);
            }
        }

        [TestMethod]
        public void OpenClickedTest()
        {
            IEventRaiser openEvent;

            using (this.mocks.Record())
            {
                this.view.OpenClicked += null;
                LastCall.IgnoreArguments();
                openEvent = LastCall.GetEventRaiser();
            }

            using (this.mocks.Playback())
            {
                var presenter = this.CreatePresenter();

                bool fileOpenedEventRaised = false;
                presenter.FileOpened += (o, e) => { fileOpenedEventRaised = true; };

                openEvent.Raise(null, null);
                Assert.IsTrue(fileOpenedEventRaised);
            }
        }

        [TestMethod]
        public void FilePathTestGet()
        {
            //presenter should simply return the file path displayed by the view
            Expect.Call(this.view.FilePathText).Return(@"C:\somefilepath\somefile.txt");
            this.mocks.ReplayAll();

            var presenter = this.CreatePresenter();
            Assert.AreEqual(@"C:\somefilepath\somefile.txt", presenter.FilePath);
        }

        [TestMethod]
        public void InitialDirectoryTestGet()
        {
            Expect.Call(this.openDialog.InitialDirectory).Return(@"C:\initialdirectory");
            this.mocks.ReplayAll();

            var presenter = this.CreatePresenter();
            Assert.AreEqual(@"C:\initialdirectory", presenter.InitialDirectory);
        }

        [TestMethod]
        public void IntialDirectoryTestSet()
        {
            //presenter should pass the intial directory on to the dialog
            this.openDialog.InitialDirectory = @"C:\initialdirectory";

            this.mocks.ReplayAll();

            var presenter = this.CreatePresenter();
            presenter.InitialDirectory = @"C:\initialdirectory";
        }

        private FileBrowserPresenter CreatePresenter()
        {
            return new FileBrowserPresenter(this.view, this.openDialog);
        }
    }
}
